﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Common.Library.Helper
{
    /// <summary>
    /// 程序集助手类
    /// </summary>
    public class AssemblyHelper
    {
        /// <summary>
        /// 单例缓存字典
        /// </summary>
        private static readonly Dictionary<string, object> CacheDic = new Dictionary<string, object>();

        /// <summary>
        /// 单例缓存的程序集字典
        /// </summary>
        private static readonly Dictionary<string, Assembly> CacheAssemblyDic = new Dictionary<string, Assembly>();

        /// <summary>
        /// 注册程序集
        /// </summary>
        /// <param name="name"></param>
        /// <param name="instantce"></param>
        public static void RegisterAssembly(string name, Assembly instantce) => CacheAssemblyDic[name] = instantce;

        /// <summary>
        /// 单例注册
        /// </summary>
        /// <param name="name"></param>
        /// <param name="instance"></param>
        public static void Register(string name, object instance) => CacheDic[name] = instance;

        /// <summary>
        /// 通过Key查找单例注册的程序集
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public static Assembly ResolveAssemblyByKey(string key)
        {
            if (CacheAssemblyDic.TryGetValue(key, out var value))
            {
                return value;
            }

            return null;
        }

        /// <summary>
        /// 优先通过Key查找单例注册的程序集，若查找的程序集不存在则创建内部实例，并做单例注册
        /// </summary>
        /// <param name="assemblyString"> 程序集的长格式名称 </param>
        /// <param name="key">要搜索的Key 若该参数为空，则默认使用参数 strClassFullName 的值</param>
        /// <returns></returns>
        public static Assembly ResolveAssemblyOrCrateByKey(string assemblyString, string key = "")
        {
            if (string.IsNullOrEmpty(key))
            {
                key = assemblyString;
            }
            Assembly value = ResolveAssemblyByKey(key);
            if (value != null)
            {
                return value;
            }
            else
            {
                value = CreateAssemblyInstance(assemblyString);
                return value;
            }
        }

        /// <summary>
        /// 创建程序集的单实例并返回创建的程序集
        /// </summary>
        /// <param name="assemblyString">程序集的长格式字符串</param>
        /// <returns></returns>
        public static Assembly CreateAssemblyInstance(string assemblyString)
        {
            try
            {
                Assembly assembly = Assembly.Load(assemblyString);
                RegisterAssembly(assemblyString, assembly);
                return assembly;
            }
            catch
            {
                return null;
            }
        }


        /// <summary>
        /// 通过Key查找单例注册的程序
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public static object ResolveByKey(string key)
        {
            if (CacheDic.TryGetValue(key, out var value))
            {
                return value;
            }

            return null;
        }

        /// <summary>
        /// 优先通过Key查找单例注册的程序，若查找的程序集不存在则仅创建内部实例，不做单例注册
        /// </summary>
        /// <param name="assemblyString">程序集的长格式名称</param>
        /// <param name="strClassFullName">类的全名 命名控件.类名 </param>
        /// <param name="key">要搜索的Key 若该参数为空，则默认使用参数 strClassFullName 的值</param>
        /// <returns></returns>
        public static object ResolveOrCrateByKey(string assemblyString,string strClassFullName, string key = "")
        {
            if (string.IsNullOrEmpty(key))
            {
                key = assemblyString + "." + strClassFullName;
            }
            if (CacheDic.TryGetValue(key, out var value))
            {
                return value;
            }
            else
            {
                return CreateInstance(assemblyString,strClassFullName);
            }
        }

        /// <summary>
        /// 创建实例
        /// </summary>
        /// <param name="assemblyString">程序集的长格式名称</param>
        /// <param name="strClassFullName">类的全名 命名空间.类名 </param>
        /// <param name="args"> 创建类实例构造参数的参数数组 为null 则more调用构造参数 </param>
        /// <returns></returns>
        public static object CreateInstance(string assemblyString, string strClassFullName,object[] args = null)
        {
            try
            {
                Assembly assembly = ResolveAssemblyOrCrateByKey(assemblyString);
                var type = assembly.GetType(strClassFullName);
                return type == null ? null : Activator.CreateInstance(type, args);
            }
            catch
            {
                return null;
            }
        }
    }
}
